package com.yupi.usercenter.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yupi.usercenter.model.domain.ChatMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket服务类 - 用户私聊功能
 *
 * @author yupi
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/chat/{userId}")
public class WebSocketService  implements ApplicationContextAware {


    /**
     * Spring应用上下文
     */
    private static ApplicationContext applicationContext;

    /**
     * 用于JSON序列化和反序列化
     */
    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 记录当前在线连接数
     */
    private static final AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 存储用户ID和WebSocket会话的映射关系
     * key: 用户ID, value: WebSocket会话
     */
    private static final Map<Long, Session> userSessionMap = new ConcurrentHashMap<>();

    /**
     * 当前会话对象
     */
    private Session session;

    /**
     * 当前用户ID
     */
    private Long userId;


    /**
     * 连接建立成功调用的方法
     *
     * @param session WebSocket会话对象
     * @param userId 用户ID
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Long userId) {
        this.session = session;
        this.userId = userId;
        // 将用户会话添加到映射中
        userSessionMap.put(userId, session);
        UserService userService = getBean(UserService.class);
        log.info("用户{}建立私聊连接，当前在线用户数：{}", userService.getById(userId).getUsername(), onlineCount.incrementAndGet());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (userId != null) {
            // 从用户映射中移除
            userSessionMap.remove(userId);
            UserService userService = getBean(UserService.class);
            log.info("用户{}断开私聊连接，当前在线用户数：{}", userService.getById(userId).getUsername(), onlineCount.decrementAndGet());
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送的消息
     */
    @OnMessage
    public void onMessage(String message) {
        try {
            // 解析消息内容
            ChatMessageData messageData = objectMapper.readValue(message, ChatMessageData.class);
            // 设置发送人ID（从当前会话获取）
            messageData.setUserId(userId);
            // 设置聊天类型为私聊
            messageData.setType(1);
            // 发送私聊消息
            sendPrivateMessage(messageData);

        } catch (Exception e) {
            log.error("处理消息时发生错误：", e);
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误：", error);
    }

    /**
     * 发送私聊消息
     *
     * @param messageData 消息数据，relatedId为目标用户ID
     */
    private void sendPrivateMessage(ChatMessageData messageData) {
        // relatedId就是目标用户ID
        Long targetUserId = messageData.getRelatedId();
        Session targetSession = userSessionMap.get(targetUserId);
        UserService userService = getBean(UserService.class);

        // 无论用户是否在线，都先保存到数据库
        try {
            // 获取ChatMessageService
            ChatMessageService chatMessageService = getBean(ChatMessageService.class);
            // 转换为数据库实体
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setUserId(messageData.getUserId());
            chatMessage.setRelatedId(messageData.getRelatedId());
            chatMessage.setMessage(messageData.getMessage());
            chatMessage.setType(messageData.getType());
            chatMessage.setPublishTime(new Date());
            // 保存到数据库
            chatMessageService.save(chatMessage);

            log.info("消息已保存到数据库：{} -> {}", userService.getById(userId).getUsername(), userService.getById(targetUserId).getUsername());

        } catch (Exception e) {
            log.error("保存消息到数据库失败：", e);
            sendMessageToSender("消息发送失败", false);
            return; // 如果保存失败，直接返回，不进行后续操作
        }

        // 检查目标用户是否在线
        if (targetSession != null && targetSession.isOpen()) {
            // 目标用户在线，实时发送消息
            try {
                //替换messageData的值，返回用户的名字和头像
                targetSession.getBasicRemote().sendText(objectMapper.writeValueAsString(messageData));
                log.info("私聊消息实时发送成功：{} -> {}", userService.getById(userId).getUsername(), userService.getById(targetUserId).getUsername());

                // 给发送者确认消息
                sendMessageToSender("消息发送成功", true);

            } catch (IOException e) {
                log.error("发送私聊消息失败：", e);
                sendMessageToSender("消息已保存，但实时发送失败", false);
            }
        } else {
            // 目标用户不在线，只保存到数据库
            log.info("目标用户{}不在线，消息已保存到数据库", userService.getById(targetUserId).getUsername());
            sendMessageToSender("消息已发送，对方不在线", true);
        }
    }
    /**
     * 给发送者发送确认消息
     */
    private void sendMessageToSender(String message, boolean success) {
        try {
            ChatMessageData response = new ChatMessageData();
            response.setUserId(0L); // 系统消息
            response.setRelatedId(userId);
            response.setMessage(message);
            response.setType(1);

            session.getBasicRemote().sendText(objectMapper.writeValueAsString(response));
        } catch (IOException e) {
            log.error("发送确认消息失败：", e);
        }
    }

    /**
     * 设置Spring应用上下文
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        WebSocketService.applicationContext = applicationContext;
    }

    /**
     * 获取Spring Bean
     */
    private static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 获取在线用户ID列表
     */
    public static List<Long> getOnlineUserIds() {
        return new ArrayList<>(userSessionMap.keySet());
    }

    /**
     * 聊天消息数据结构
     * 对应数据库表 chat_message
     */
    public static class ChatMessageData {
        private Long id;
        private Long userId;        // 发送者ID（从会话中自动获取）
        private Long relatedId;     // 目标用户ID
        private String message;     // 聊天内容
        private String publishTime; // 发布时间
        private Integer type;       // 聊天类型(1私聊)

        // getter和setter方法
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public Long getUserId() { return userId; }
        public void setUserId(Long userId) { this.userId = userId; }
        public Long getRelatedId() { return relatedId; }
        public void setRelatedId(Long relatedId) { this.relatedId = relatedId; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public String getPublishTime() { return publishTime; }
        public void setPublishTime(String publishTime) { this.publishTime = publishTime; }
        public Integer getType() { return type; }
        public void setType(Integer type) { this.type = type; }
    }
}